package com.york.tinyrpc.proto.server;

import com.york.tinyrpc.proto.model.TinyRpcRequest;
import com.york.tinyrpc.proto.model.TinyRpcResponse;
import com.york.tinyrpc.proto.registry.LocalRegistry;
import com.york.tinyrpc.proto.serializer.JdkSerializer;
import com.york.tinyrpc.proto.serializer.Serializer;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.reflect.Method;

/**
 * 请求处理器，执行流程如下
 * 1. 反序列化【请求】为对象，并从请求对象中获取参数
 * 2. 根据服务名称从【本地注册器】中获取到对应的【服务实现类】
 * 3. 通过反射机制调用方法，得到返回结果
 * 4. 对返回结果进行封装和序列化，并写入到【响应】中
 */
public class HttpServerHandler implements Handler<HttpServerRequest> {

    private static final Logger log = LoggerFactory.getLogger(HttpServerHandler.class);

    /**
     * 请求执行方法
     *
     * @param request
     */
    @Override
    public void handle(HttpServerRequest request) {
        // 指定序列化器，完成对出入参序列化
        final Serializer serializer = new JdkSerializer();

        log.info("Received request:{}, request.method:{}, request.url:{}",
                request, request.method(), request.uri());

        // 异步处理http请求
        request.bodyHandler(body -> {
            TinyRpcRequest deserializeRequest = null;

            // 反序列化为RPC请求实体
            try {
                deserializeRequest = serializer.deserialize(body.getBytes(), TinyRpcRequest.class);
            } catch (IOException e) {
                log.error("反序列化失败:{}", e.getMessage());
            }

            TinyRpcResponse response = new TinyRpcResponse();
            if (null == deserializeRequest) {
                // 如果请求为空，则这次调用结束即可
                log.warn("请求参数为空");
                response.setMessage("请求参数为空");
                // 响应给调用方
                doResponse(request, response, serializer);
                return;
            }

            try {
                // 获取要调用的服务实现类，通过反射调用
                Class<?> implClass = LocalRegistry.getService(deserializeRequest.getServiceName());
                Method method = implClass.getMethod(deserializeRequest.getMethodName(),
                        deserializeRequest.getParameterTypes());
                Object result = method.invoke(implClass.newInstance(), deserializeRequest.getArgs());
                // 封装返回结果
                response.setData(result);
                response.setDataType(method.getReturnType());
                response.setMessage("TinyRPC called succeed");
                log.info("TinyRPC 调用成功, rpcRequest:{}, rpcResponse:{}", deserializeRequest, response);
            } catch (Exception e) {
                response.setException(e);
                response.setMessage(e.getMessage());
                log.error("TinyRPC 调用失败, rpcRequest:{}, rpcResponse:{}", deserializeRequest, response);
            }

            // 响应给调用方
            doResponse(request, response, serializer);
        });
    }

    /**
     * 响应给调用方
     * 期间将TinyRpcResponse序列化转化为Buffer
     * 交由Vert.x返回给调用方
     *
     * @param request
     * @param rpcResponse
     * @param serializer
     */
    void doResponse(HttpServerRequest request, TinyRpcResponse rpcResponse, Serializer serializer) {
        HttpServerResponse httpServerResponse = request.response()
                .putHeader("content-type", "application/json");

        try {
            // 将RPC调用结果序列化，用于传输给调用方
            httpServerResponse.end(Buffer.buffer(serializer.serialize(rpcResponse)));
        } catch (IOException e) {
            e.printStackTrace();
            httpServerResponse.end(Buffer.buffer());
        }
    }
}
